/*
 * @[H]:  Copyright (c) 2021 Phytium Information Technology, Inc. 
 * 
 *  SPDX-License-Identifier: Apache-2.0. 
 * 
 * @Date: 2021-07-20 18:40:42
 * @LastEditTime: 2021-07-22 21:08:54
 * @Description:  Description of file
 * @Modify History: 
 * * * Ver   Who        Date         Changes
 * * ----- ------     --------    --------------------------------------
 */

#ifndef DRIVERS_ETH_F_XMAC_BDRING_H
#define DRIVERS_ETH_F_XMAC_BDRING_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "f_xmac_bd.h"
#include "ft_types.h"

    /**************************** Type Definitions *******************************/

    /** This is an internal structure used to maintain the DMA list */
    typedef struct
    {
        uintptr phys_base_addr; /**< Physical address of 1st BD in list */
        uintptr base_bd_addr;   /**< Virtual address of 1st BD in list */
        uintptr high_bd_addr;   /**< Virtual address of last BD in the list */
        u32 length;             /**< Total size of ring in bytes */
        u32 run_state;          /**< Flag to indicate DMA is started */
        u32 separation;         /**< Number of bytes between the starting address
                                  of adjacent BDs */
        FXmacBd *free_head;
        /**< First BD in the free group */
        FXmacBd *pre_head; /**< First BD in the pre-work group */
        FXmacBd *hw_head;  /**< First BD in the work group */
        FXmacBd *hw_tail;  /**< Last BD in the work group */
        FXmacBd *post_head;
        /**< First BD in the post-work group */
        FXmacBd *bda_restart;
        /**< BDA to load when channel is started */

        volatile u32 hw_cnt; /**< Number of BDs in work group */
        u32 pre_cnt;         /**< Number of BDs in pre-work group */
        u32 free_cnt;        /**< Number of allocatable BDs in the free group */
        u32 post_cnt;        /**< Number of BDs in post-work group */
        u32 all_cnt;         /**< Total Number of BDs for channel */
    } FXmacBdRing;

/****************************************************************************/
/**
* Return the next BD from bd_ptr in a list.
*
* @param  ring_ptr is the DMA channel to operate on.
* @param  bd_ptr is the BD to operate on.
*
* @return The next BD in the list relative to the bd_ptr parameter.
*
* @note
* C-style signature:
*    FXmacBd *FXmacBdRingNext(FXmacBdRing* ring_ptr,
*                                      FXmacBd *bd_ptr)
*
*****************************************************************************/
#define FXmacBdRingNext(ring_ptr, bd_ptr) \
    (((uintptr)((void *)(bd_ptr)) >= (ring_ptr)->high_bd_addr) ? (FXmacBd *)((void *)(ring_ptr)->base_bd_addr) : (FXmacBd *)((uintptr)((void *)(bd_ptr)) + (ring_ptr)->separation))

/*****************************************************************************/
/**
* Use this macro at initialization time to determine how many BDs will fit
* in a BD list within the given memory constraints.
*
* The results of this macro can be provided to FXmacBdRingCreate().
*
* @param alignment specifies what byte alignment the BDs must fall on and
*        must be a power of 2 to get an accurate calculation (32, 64, 128,...)
* @param Bytes is the number of bytes to be used to store BDs.
*
* @return Number of BDs that can fit in the given memory area
*
* @note
* C-style signature:
*    u32 FXmacBdRingCntCalc(u32 alignment, u32 Bytes)
*
******************************************************************************/
#define FXmacBdRingCntCalc(alignment, Bytes) \
    (u32)((Bytes) / (sizeof(FXmacBd)))

/*****************************************************************************/
/**
* Use this macro at initialization time to determine how many bytes of memory
* is required to contain a given number of BDs at a given alignment.
*
* @param alignment specifies what byte alignment the BDs must fall on. This
*        parameter must be a power of 2 to get an accurate calculation (32, 64,
*        128,...)
* @param num_bd is the number of BDs to calculate memory size requirements for
*
* @return The number of bytes of memory required to create a BD list with the
*         given memory constraints.
*
* @note
* C-style signature:
*    u32 FXmacBdRingMemCalc(u32 alignment, u32 num_bd)
*
******************************************************************************/
#define FXmacBdRingMemCalc(alignment, num_bd) \
    (u32)(sizeof(FXmacBd) * (num_bd))

/****************************************************************************/
/**
* Return the total number of BDs allocated by this channel with
* FXmacBdRingCreate().
*
* @param  ring_ptr is the DMA channel to operate on.
*
* @return The total number of BDs allocated for this channel.
*
* @note
* C-style signature:
*    u32 FXmacBdRingGetCnt(FXmacBdRing* ring_ptr)
*
*****************************************************************************/
#define FXmacBdRingGetCnt(ring_ptr) ((ring_ptr)->AllCnt)

/****************************************************************************/
/**
* Return the number of BDs allocatable with FXmacBdRingAlloc() for pre-
* processing.
*
* @param  ring_ptr is the DMA channel to operate on.
*
* @return The number of BDs currently allocatable.
*
* @note
* C-style signature:
*    u32 FXmacBdRingGetFreeCnt(FXmacBdRing* ring_ptr)
*
*****************************************************************************/
#define FXmacBdRingGetFreeCnt(ring_ptr) ((ring_ptr)->FreeCnt)

/****************************************************************************/
/**
* Return the next BD from bd_ptr in a list.
*
* @param  ring_ptr is the DMA channel to operate on.
* @param  bd_ptr is the BD to operate on.
*
* @return The next BD in the list relative to the bd_ptr parameter.
*
* @note
* C-style signature:
*    FXmacBd *FXmacBdRingNext(FXmacBdRing* ring_ptr,
*                                      FXmacBd *bd_ptr)
*
*****************************************************************************/
#define FXmacBdRingNext(ring_ptr, bd_ptr) \
    (((uintptr)((void *)(bd_ptr)) >= (ring_ptr)->high_bd_addr) ? (FXmacBd *)((void *)(ring_ptr)->base_bd_addr) : (FXmacBd *)((uintptr)((void *)(bd_ptr)) + (ring_ptr)->separation))

/****************************************************************************/
/**
* Return the previous BD from bd_ptr in the list.
*
* @param  ring_ptr is the DMA channel to operate on.
* @param  bd_ptr is the BD to operate on
*
* @return The previous BD in the list relative to the bd_ptr parameter.
*
* @note
* C-style signature:
*    FXmacBd *FXmacBdRingPrev(FXmacBdRing* ring_ptr,
*                                      FXmacBd *bd_ptr)
*
*****************************************************************************/
#define FXmacBdRingPrev(ring_ptr, bd_ptr) \
    (((uintptr)(bd_ptr) <= (ring_ptr)->base_bd_addr) ? (FXmacBd *)(ring_ptr)->high_bd_addr : (FXmacBd *)((uintptr)(bd_ptr) - (ring_ptr)->separation))

    /************************** Function Prototypes ******************************/

    /*
 * Scatter gather DMA related functions in FXmacbdring.c
 */
    LONG FXmacBdRingCreate(FXmacBdRing *ring_ptr, uintptr phys_addr,
                           uintptr virt_addr, u32 alignment, u32 bd_count);
    LONG FXmacBdRingClone(FXmacBdRing *ring_ptr, FXmacBd *src_bd_ptr,
                          u8 direction);
    LONG FXmacBdRingAlloc(FXmacBdRing *ring_ptr, u32 num_bd,
                          FXmacBd **bd_set_ptr);
    LONG FXmacBdRingUnAlloc(FXmacBdRing *ring_ptr, u32 num_bd,
                            FXmacBd *bd_set_ptr);
    LONG FXmacBdRingToHw(FXmacBdRing *ring_ptr, u32 num_bd,
                         FXmacBd *bd_set_ptr);
    LONG FXmacBdRingFree(FXmacBdRing *ring_ptr, u32 num_bd,
                         FXmacBd *bd_set_ptr);
    u32 FXmacBdRingFromHwTx(FXmacBdRing *ring_ptr, u32 bd_limit,
                            FXmacBd **bd_set_ptr);
    u32 FXmacBdRingFromHwRx(FXmacBdRing *ring_ptr, u32 bd_limit,
                            FXmacBd **bd_set_ptr);
    LONG FXmacBdRingCheck(FXmacBdRing *ring_ptr, u8 direction);

    void FXmacBdring_ptrReset(FXmacBdRing *ring_ptr, void *virt_addrloc);

#ifdef __cplusplus
}
#endif

#endif